package com.flynn.rock.crm.service.customer.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.flynn.rock.crm.convert.AbstractCustomerConvert;
import com.flynn.rock.crm.entity.customer.CustomerEntity;
import com.flynn.rock.crm.entity.customer.CustomerOrderEntity;
import com.flynn.rock.crm.model.customer.request.CancelledCustomerOrderRequest;
import com.flynn.rock.crm.model.customer.request.FinishedCustomerOrderRequest;
import com.flynn.rock.crm.model.customer.request.NewInvitationRequest;
import com.flynn.rock.crm.model.customer.request.PageCustomerOrderRequest;
import com.flynn.rock.crm.model.customer.request.SignedCustomerOrderRequest;
import com.flynn.rock.crm.model.customer.request.VisitedCustomerOrderRequest;
import com.flynn.rock.crm.model.customer.vo.CustomerOrderIdVo;
import com.flynn.rock.crm.model.customer.vo.CustomerOrderVo;
import com.flynn.rock.crm.repository.customer.CustomerOrderRepository;
import com.flynn.rock.crm.repository.customer.CustomerRepository;
import com.flynn.rock.crm.service.customer.BusinessService;
import com.flynn.rock.enums.customer.CustomerOrderStatus;
import com.flynn.rock.enums.customer.CustomerStatus;
import com.flynn.rock.model.PageResult;
import com.flynn.rock.util.PageUtil;
import jakarta.annotation.Resource;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class BusinessServiceImpl implements BusinessService {

    @Resource
    private CustomerRepository customerRepository;

    @Resource
    private CustomerOrderRepository customerOrderRepository;

    @Override
    public CustomerOrderIdVo invitationCustomerOrder(NewInvitationRequest request) {
        CustomerEntity customerEntity = customerRepository.findById(request.getCustomerId()).orElseThrow();
        if (customerOrderRepository.existsByCustomerIdAndOrderStatusIn(request.getCustomerId(), CustomerOrderStatus.NOT_END_STATUS)) {
            throw new RuntimeException("当前客户已存在正在生效的邀约");
        }
        CustomerOrderEntity customerOrderEntity = AbstractCustomerConvert.INSTANCE.toCustomerOrderEntity(request);
        customerOrderEntity.setCustomerCode(customerEntity.getCustomerCode());
        customerOrderEntity.setCustomerName(customerEntity.getCustomerName());
        customerOrderEntity.setPhone(customerEntity.getPhone());
        customerOrderEntity = customerOrderRepository.save(customerOrderEntity);
        customerEntity.setStatus(CustomerStatus.FOLLOW_UP);
        customerEntity.setFollowUpStatus(CustomerOrderStatus.invitation);
        customerEntity.setLastFollowUpTime(LocalDateTime.now());
        customerRepository.save(customerEntity);
        return new CustomerOrderIdVo(customerOrderEntity.getCustomerOrderId());
    }

    @Override
    public CustomerOrderIdVo visitedCustomerOrder(VisitedCustomerOrderRequest request) {
        CustomerOrderEntity customerOrderEntity = customerOrderRepository.findById(request.getCustomerOrderId()).orElseThrow();
        LocalDateTime actualVisitTime = LocalDateTimeUtil.of(request.getActualVisitTime());
        customerOrderEntity.setActualVisitTime(actualVisitTime);
        customerOrderEntity.setRemark(request.getRemark());
        customerOrderEntity.setOrderStatus(CustomerOrderStatus.visited);
        customerOrderRepository.save(customerOrderEntity);
        CustomerEntity customerEntity = customerRepository.findById(customerOrderEntity.getCustomerId()).orElseThrow();
        customerEntity.setFollowUpStatus(CustomerOrderStatus.visited);
        customerEntity.setLastFollowUpTime(LocalDateTime.now());
        customerRepository.save(customerEntity);
        return new CustomerOrderIdVo(customerOrderEntity.getCustomerOrderId());
    }

    @Override
    public CustomerOrderIdVo signedCustomerOrder(SignedCustomerOrderRequest request) {
        CustomerOrderEntity customerOrderEntity = customerOrderRepository.findById(request.getCustomerOrderId()).orElseThrow();
        LocalDateTime expectLoanLimitTime = LocalDateTimeUtil.of(request.getExpectLoanLimitTime());
        customerOrderEntity.setExpectLoanLimitTime(expectLoanLimitTime);
        customerOrderEntity.setExpectLoanLimit(request.getExpectLoanLimit());
        customerOrderEntity.setRemark(request.getRemark());
        customerOrderEntity.setOrderStatus(CustomerOrderStatus.signed);
        customerOrderRepository.save(customerOrderEntity);
        CustomerEntity customerEntity = customerRepository.findById(customerOrderEntity.getCustomerId()).orElseThrow();
        customerEntity.setFollowUpStatus(CustomerOrderStatus.signed);
        customerEntity.setLastFollowUpTime(LocalDateTime.now());
        customerRepository.save(customerEntity);
        return new CustomerOrderIdVo(customerOrderEntity.getCustomerOrderId());
    }

    @Override
    public CustomerOrderIdVo finishedCustomerOrder(FinishedCustomerOrderRequest request) {
        CustomerOrderEntity customerOrderEntity = customerOrderRepository.findById(request.getCustomerOrderId()).orElseThrow();
        LocalDateTime actualLoanLimitTime = LocalDateTimeUtil.of(request.getActualLoanLimitTime());
        customerOrderEntity.setActualLoanLimitTime(actualLoanLimitTime);
        customerOrderEntity.setActualLoanLimit(request.getActualLoanLimit());
        customerOrderEntity.setRemark(request.getRemark());
        customerOrderEntity.setOrderStatus(CustomerOrderStatus.finished);
        customerOrderRepository.save(customerOrderEntity);
        CustomerEntity customerEntity = customerRepository.findById(customerOrderEntity.getCustomerId()).orElseThrow();
        customerEntity.setStatus(CustomerStatus.SIGNED);
        customerEntity.setFollowUpStatus(CustomerOrderStatus.finished);
        customerEntity.setLastFollowUpTime(LocalDateTime.now());
        customerRepository.save(customerEntity);
        return new CustomerOrderIdVo(customerOrderEntity.getCustomerOrderId());
    }

    @Override
    public CustomerOrderIdVo cancelledCustomerOrder(CancelledCustomerOrderRequest request) {
        CustomerOrderEntity customerOrderEntity = customerOrderRepository.findById(request.getCustomerOrderId()).orElseThrow();
        customerOrderEntity.setRemark(request.getRemark());
        customerOrderEntity.setOrderStatus(CustomerOrderStatus.cancelled);
        customerOrderRepository.save(customerOrderEntity);
        CustomerEntity customerEntity = customerRepository.findById(customerOrderEntity.getCustomerId()).orElseThrow();
        customerEntity.setStatus(CustomerStatus.FOLLOW_UP);
        customerEntity.setFollowUpStatus(CustomerOrderStatus.cancelled);
        customerEntity.setLastFollowUpTime(LocalDateTime.now());
        customerRepository.save(customerEntity);
        return new CustomerOrderIdVo(customerOrderEntity.getCustomerOrderId());
    }

    @Override
    public PageResult<CustomerOrderVo> pageCustomerOrder(PageCustomerOrderRequest request) {
        PageRequest pageRequest = PageRequest.of(request.getPageNum() - 1, request.getPageSize());
        pageRequest = pageRequest.withSort(
                Sort.sort(CustomerOrderEntity.class).by(CustomerOrderEntity::getUpdateTime).descending()
        );
        Page<CustomerOrderEntity> entityPage = customerOrderRepository.findAll(
                ((root, query, criteriaBuilder) -> {
                    List<Predicate> predicates = new ArrayList<>();
                    Path<Object> orderStatus = root.get("orderStatus");
                    if (StrUtil.isNotBlank(request.getCustomerName())) {
                        predicates.add(criteriaBuilder.like(root.get("customerName"), "%" + request.getCustomerName() + "%"));
                    }
                    if (StrUtil.isNotBlank(request.getCustomerCode())) {
                        predicates.add(criteriaBuilder.like(root.get("customerCode"), "%" + request.getCustomerCode() + "%"));
                    }
                    if (StrUtil.isNotBlank(request.getPhone())) {
                        predicates.add(criteriaBuilder.like(root.get("phone"), "%" + request.getPhone() + "%"));
                    }
                    predicates.add(criteriaBuilder.notEqual(orderStatus, CustomerOrderStatus.cancelled));
                    if (Objects.nonNull(request.getOrderStatus())) {
                        predicates.add(criteriaBuilder.equal(orderStatus, request.getOrderStatus()));
                    }
                    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
                }),
                pageRequest
        );
        return PageUtil.toPage(entityPage.map(AbstractCustomerConvert.INSTANCE::toCustomerOrderVo));
    }

    @Override
    public CustomerOrderVo getCustomerOrder(Long customerOrderId) {
        CustomerOrderEntity customerOrderEntity = customerOrderRepository.findById(customerOrderId).orElseThrow();
        return AbstractCustomerConvert.INSTANCE.toCustomerOrderVo(customerOrderEntity);
    }

    @Override
    public void deleteCustomerOrder(Long customerOrderId) {
        CustomerOrderEntity customerOrderEntity = customerOrderRepository.findById(customerOrderId).orElseThrow();
        customerOrderRepository.delete(customerOrderEntity);
    }
}
